import java.util.*;
import java.io.*;

/**
* ScannerII creates a language instance
* and runs the input through its parsing
* table.
*/
public class ScannerII{
	
	/**
	* Constructor
	* @param fileName the file with the given language
	*/
	public ScannerII(String fileName){
		File file = new File(fileName); //create the file
		Language l = new Language(file); //create the language
// 		l.parsingTable.PrintTable(); //to view parsing table 
		File input = new File("output.txt"); //find the input (the output.txt from ScannerI)
		Stack stack = new Stack(); //create a stack for the input
		fillStack(input, stack); //put the input text into the stack
		boolean success=runTable(l, stack); //run the stack through the parsing table
		if(success){ //check for success
			System.out.println("Successful parse!");
		}
		
		System.out.println();
		System.out.println("Parsing Table (CSV Format):");
		l.parsingTable.PrintCSV();
	}
	
	/**
	* Fills the given stack with the words from the given input file
	* @param file an input file with the words to process
	* @param stack a stack to put the words from the file into
	*/
	public static void fillStack(File file, Stack stack){
		BufferedReader reader = null;
		ArrayList lines = new ArrayList(); //each line
		String[] tokens; //words from the line
      try {
         reader = new BufferedReader(new FileReader(file));
         String text = null;
         while ((text = reader.readLine()) != null) {
            lines.add(text); //grab each line
         }
      } 
      catch (FileNotFoundException e) {
         System.out.println("NO FILE");
      } 
       catch (IOException e) {
         e.printStackTrace();
      } 
      finally {
         try {
            if (reader != null) {
               reader.close();
            }
         } 
         catch (IOException e) {
            e.printStackTrace();
         }
      }
		for(Object line : lines){               //for each line 
			tokens=((String)line).split("[ ]+"); // split it into words
			for(int i=tokens.length-1;i>=0;i--){ // and for each word
				stack.push(tokens[i]);            // push onto the stack
			}
		}
	}
	
	/**
	* Runs the input stack through the given languages parsing table
	* @param l the language which contains the parsing table
	* @param input the stack which contains the input for the table
	*/
	public static boolean runTable(Language l, Stack input){
		boolean value = true; //return value
		Rule rule = new Rule(); //rule being worked with
		Rule oldRule = new Rule(); //temp rule
		Stack values = new Stack(); //the parsing stack
		String tail = l.parsingTable.getRule((String)l.start.get(0),"BEGIN").getTail(); //initialize the stack with the start rule's follow
		for(int i=(tail.split("[ ]+").length-1);i>=0;i--){ // for each word in the follow instructions push onto the parsing stack
			values.push(tail.split("[ ]+")[i]);
		}
		String next =""; //the next value on the parsing stack
		while(input.empty()==false){ //if you have input keep going
			if(values.peek().toString().charAt(0)!='<'){ //if the next item on the parsing stack isn't a rule...
				if(values.peek().toString().equals(input.peek().toString())){ // and it matches the input
					values.pop(); //
					input.pop();  //pop the parsing stack and the input
				}
				else{ // if it's not a rule and it doesn't match then you fail... dump the parsing stack
					value=false;
					System.out.println("ERROR PARSING "+oldRule.getHead().toString()+" with "+input.peek().toString());
					System.out.println(oldRule.getHead().toString());
					for(int i=0;i<values.size();i++){
						System.out.println(values.pop().toString());
					}
					input.clear();
				}
			}
			else{ // otherwise you're dealing with a rule
				next=values.pop().toString(); //get the rule
				oldRule.setHead(next); //set the temp rule to have this head
				rule = l.parsingTable.getRule(next,input.peek().toString()); //get the instructions from the parsing table for that rule given the input
				if(rule!=null){ //if the rule exists
					for(int i=(rule.getTail().split("[ ]+").length-1);i>=0;i--){ //for each word in the rule
						values.push(rule.getTail().split("[ ]+")[i]); //push onto the parsing stack
					}
				}
				else{ //the rule doesn't have an entry in the parsing table for that input...
					rule = l.parsingTable.getRule(next,"E"); // does the rule have an option for the empty set
					if(rule==null){ //if not the dump the stack
						value=false;
						System.out.println("ERROR PARSING "+oldRule.getHead().toString()+" with "+input.peek().toString());
						System.out.println(oldRule.getHead().toString());
						for(int i=0;i<values.size();i++){
							System.out.println(values.pop().toString());
						}
						input.clear();
					}
					//if so the parsing stack has already popped it... continue.
				}
			}			
		}
		return value; //return success or fail
	}	
}